<script>
import { Icon, Modal } from 'ant-design-vue'
import { clearSelection, createProps } from '@/utils';

const contentClass = 'ant-modal-content'
const contentWrapperClass = 'ant-modal'

export default {
  name: 'HModal',
  model: {
    prop: 'visible',
    event: 'change'
  },
  props: {
    destroyOnClose: createProps(Boolean, true),
    forceFullScreen: createProps(Boolean),
    closable: createProps(Boolean, true),
    defaultFullScreen: createProps(Boolean),
    visible: createProps(Boolean, false),
    title: createProps(String),
    width: createProps(Number, 600),
    height: createProps(Number, -1)
  },
  data () {
    return {
      fullScreen: false,
      left: -1,
      top: -1,
      innerWidth: 600,
      innerHeight: -1,
      firstRender: true
    }
  },
  render (h) {
    this.beforeRender()
    return h(Modal, {
      class: ['h-modal', { 'h-modal_full_screen': this.fullScreen, 'h-modal-move-able': !this.fullScreen }],
      props: {
        ...this.$attrs,
        ...this.$props,
        closable: false,
        title: undefined,
        width: this.innerWidth,
        dialogStyle: { top: this.initingFullScreen ? 0 : '100px' }
      },
      attrs: {
        ...this.$attrs,
        ...this.$props,
        title: undefined
      },
      on: {
        ...this.$listeners
      }
    }, [this.wrapBody(h, (this.$slots.default || [])), this.createHeader(h), ...this.getSlots(h)])
  },
  mounted () {
    this.resolveWindowWidth()
  },
  beforeDestroy () {
    this.disObserveResize()
  },
  methods: {
    wrapBody(h, child) {
      let overFlow = this.height > 0 ? 'auto' : undefined;
      let height = this.height > 0 ? `${this.height - 125}px` : 'fit-content';
      if (this.fullScreen) {
        height = 'calc(100vh - 125px)';
        overFlow = undefined;
      }
      return h('div', {class: 'h-modal-body-wrapper', style: {height, overFlow}}, child);
    },
    getSlots (h) {
      let slotMap = this.$slots, res = []
      for (let key in slotMap) {
        if ((key === 'default' || key === 'title')
            || (!slotMap[key] || slotMap[key].length <= 0)) continue
        res.push(h('template', {slot: key}, slotMap[key]))
      }
      return res
    },
    disObserveResize () {
      this.observer && this.observer.disconnect()
    },
    observeResize () {
      let that = this
      this.observer = new ResizeObserver(() => {
        if(!that.getContentElement()) return
        let left = this.left
        if (left < (that.innerWidth / 2) - (window.innerWidth / 2)) {
          left = (that.innerWidth / 2) - (window.innerWidth / 2)
        }
        if (left > (window.innerWidth / 2) - (that.innerWidth / 2)) {
          left = (window.innerWidth / 2) - (that.innerWidth / 2)
        }
        that.left = left
        let top = this.top
        if (top < -100) top = -100
        if (top > window.innerHeight - 100 - that.getContentElement().offsetHeight) {
          top = window.innerHeight - 100 - that.getContentElement().offsetHeight
        }
        that.top = top
        that.resolveWindowWidth()
      })
      this.observer.observe(document.body)
    },
    beforeRender () {
      if (this.fullScreen && this.firstRender) {
        this.innerWidth = window.innerWidth
        this.innerHeight = window.innerHeight
        this.initingFullScreen = true
        this.firstRender = false

        setTimeout(() => {
          this.initingFullScreen = false
          if (this.innerWidth !== this.width) {
            this.innerWidth = this.width
          }
          if (this.innerWidth !== this.width) {
            this.innerWidth = this.width
          }
          this.innerHeight = this.height
          this.fullScreen = true
        }, 800)
      }
    },
    getContentElement () {
      let el = this.$refs.buttonWrapper
      if (!el) return
      while (el && !(new Set(el.classList).has(contentClass))) {
        el = el.parentNode
      }
      return el
    },
    resolveWindowWidth () {
      this.$nextTick(() => {
        let el = this.getContentElement()
        if (!el) return
        if (!el.style) el.style = {}
        el.style.removeProperty('height')
        el.style.removeProperty('left')
        el.style.removeProperty('top')
        el.style.removeProperty('width')
        el.style.removeProperty('max-height')

        el.style.width = this.windowWidth
        el.style.height = this.windowHeight
        el.style.left = this.windowLeft
        el.style.top = this.windowTop
        el.style.maxHeight = this.windowMaxHeight
      })
    },
    createHeader (h) {
      if(!this.title && !this.$slots.title) return undefined
      return h('div', {
        class: ['h-modal-title-wrapper'],
        slot: 'title',
        on: {
          dblclick: () => this.toggleFull(),
          mousedown: (e) => this.dragStart(e)
        }
      }, [this.createTitle(h), this.createButtons(h)])
    },
    dragStart (e) {
      let { clientX: startX, clientY: startY } = e
      let el = this.getContentElement()
      if(!el) return
      this.left = parseInt(window.getComputedStyle(el).left.replace('px', ''))
      this.top = parseInt(window.getComputedStyle(el).top.replace('px', ''))

      let startLeft = this.left, startTop = this.top
      let that = this

      function mouseup (e) {
        window.removeEventListener('mousemove', move)
        window.removeEventListener('mouseup', mouseup)
        document.body.style.removeProperty('user-select')
      }

      function move (e) {
        let { clientX: endX, clientY: endY } = e
        let left = startLeft + endX - startX

        if (left < (that.innerWidth / 2) - (window.innerWidth / 2)) {
          left = (that.innerWidth / 2) - (window.innerWidth / 2)
        }

        if (left > (window.innerWidth / 2) - (that.innerWidth / 2)) {
          left = (window.innerWidth / 2) - (that.innerWidth / 2)
        }
        that.left = left

        let top = startTop + endY - startY
        if (top < -100) top = -100
        if (top > window.innerHeight - 100 - that.getContentElement().offsetHeight) {
          top = window.innerHeight - 100 - that.getContentElement().offsetHeight
        }
        that.top = top
        that.resolveWindowWidth()
      }

      document.body.style.userSelect = 'none'
      window.addEventListener('mousemove', move)
      window.addEventListener('mouseup', mouseup)
    },
    createTitle (h) {
      return h('div', { class: 'h-modal-title' }, [this.$slots.title || this.title])
    },
    cancel () {
      this.$emit('cancel')
    },
    toggleFull () {
      clearSelection()
      if (this.forceFullScreen) {
        this.fullScreen = true
        return

      }
      this.left = -1
      this.right = -1
      this.fullScreen = !this.fullScreen
    },
    createButtons (h) {
      return h('div', { class: 'h-model-button-wraper', ref: 'buttonWrapper' }, this.closable && [
        h(Icon, { props: { type: 'close' }, on: { click: () => this.cancel() }, class: 'h-model-button-wraper-icon' })
      ] || undefined)
    }
  },
  computed: {
    windowWidth () {
      if (this.fullScreen) return '100vw'
      return `${this.innerWidth}px`
    },
    windowHeight () {
      if (this.fullScreen) return '100vh'
      return `${this.innerHeight}px`
    },
    windowLeft () {
      if (this.fullScreen) return '0'
      if (this.left > 0) return `${this.left}px`
      return `${this.left}px`
    },
    windowTop () {
      if (this.fullScreen) return '0'
      if (this.top > 0) return `${this.top}px`
      return `${this.top}px`
    },
    windowMaxHeight () {
      if (!this.fullScreen) return 'calc(100vh)'
    }
  },
  watch: {
    fullScreen: {
      handler () {
        this.resolveWindowWidth()
      },
      immediate: true
    },
    visible: {
      handler () {
        if (this.visible) {
          this.fullScreen = this.defaultFullScreen || this.forceFullScreen
          this.firstRender = true
          this.left = 0
          this.top = 0
          this.observeResize()
        } else {
          this.disObserveResize()
        }
        this.$nextTick(() => {
          if (this.visible) {
            this.resolveWindowWidth()
          }
        })
      },
      immediate: true
    },
    height: {
      handler () {
        this.innerHeight = this.height
        this.resolveWindowWidth()
      },
      immediate: true
    },
    width: {
      handler () {
        this.innerWidth = this.width
        this.resolveWindowWidth()
      },
      immediate: true
    }
  }
}
</script>
<style>
.h-modal .ant-modal-header:hover {
  cursor: pointer;
}

.h-modal-move-able .ant-modal-header:hover{
  cursor: move;
}

.h-modal-title {
  padding-left: 20px;
  user-select: none;
  flex: 1;
}

.h-modal .h-modal-title-wrapper {
  height: 50px;
  display: flex;
  align-items: center;
}

.h-modal .ant-modal-body {
  flex: 1;
  overflow: auto;
  padding: 10px;
}

.h-modal_full_screen .ant-modal-content {
  position: fixed;
}

.h-modal .ant-modal-content {
  flex-direction: column;
  display: flex;
}

.h-modal .ant-modal-header {
  padding: 0;
  margin: 0;
}

.h-modal .ant-modal {

}

.h-modal {

}

.h-model-button-wraper {
  padding-right: 25px;
}

.h-model-button-wraper-icon {
  cursor: pointer;
  color: #8c8c8c;
  margin-left: 15px;
}

.h-model-button-wraper-icon:hover {
  color: #404040;
}


.h-modal .ant-tabs-tab {
  padding: 16px !important;
}
.h-modal .ant-tabs-bar {
  margin: 0 0 -1px 0;
}

.h-modal .ant-tabs-ink-bar {
  bottom: 2px;
}
.h-modal .ant-tabs-top-bar {

}
.h-modal .h-modal-title {
  overflow: auto;
}
</style>